#include <iostream>

#include "Model/ModelLoader.h"

namespace namespace_easy_car_ui
{

ModelLoader::ModelLoader()
{

}

ModelLoader* ModelLoader::GetInstance()
{
    static ModelLoader instance;
    return &instance;
}

ModelLoader::~ModelLoader()
{

}

Model::Ptr ModelLoader::LoadModel(const std::string& filePath)
{
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(filePath,
        aiProcess_CalcTangentSpace       |
        aiProcess_Triangulate            |
        aiProcess_JoinIdenticalVertices  |
        aiProcess_SortByPType);

    if (nullptr == scene)
    {
        std::cout << "open scene failed!" << std::endl;
        return nullptr;
    }

    aiNode* rootNode = scene->mRootNode;
    if (nullptr == rootNode)
    {
        std::cout << "There is no Node" << std::endl;
        return nullptr;
    }

    Model::Ptr retModel = std::make_shared<Model>();
    retModel->m_rootPart = std::make_shared<Part>();

    LoadOneNode(scene, rootNode, retModel->m_rootPart);

    return retModel;
}

void ModelLoader::LoadOneNode(const aiScene *scene, aiNode* node, Part::Ptr part)
{
    std::cout << "LoadOneNode name " << node->mName.C_Str() << std::endl;
    part->m_name = node->mName.C_Str();

    glm::mat4 tmpMatrix{1.0f};
    TransformMatrix4(node->mTransformation, tmpMatrix);
    part->m_transformMatrix = tmpMatrix * tmpMatrix;

    CopyMeshesToVertexes(scene, node, part);

    for (unsigned int i = 0; i < node->mNumChildren; ++i)
    {
        std::cout << "Child is " << node->mChildren[i]->mName.C_Str() << std::endl;
        Part::Ptr childPart = std::make_shared<Part>();
        LoadOneNode(scene, node->mChildren[i], childPart);
        part->m_children[node->mChildren[i]->mName.C_Str()] = childPart;
    }
}

void ModelLoader::CopyMeshesToVertexes(const aiScene *scene, aiNode* node, Part::Ptr part)
{
    for (unsigned int i = 0; i < node->mNumMeshes; ++i)
    {
        Mesh::Ptr mesh = std::make_shared<Mesh>();
        part->m_meshes.push_back(mesh);
        CopyOneMesh(scene->mMeshes[node->mMeshes[i]], mesh);
    }
}

void ModelLoader::CopyOneMesh(const aiMesh* aiMesh, Mesh::Ptr mesh)
{
    mesh->m_name = aiMesh->mName.C_Str();
    for (unsigned int i = 0; i < aiMesh->mNumVertices; ++i)
    {
        Vertex vertex;
        vertex.m_position.x = aiMesh->mVertices[i].x;
        vertex.m_position.y = aiMesh->mVertices[i].y;
        vertex.m_position.z = aiMesh->mVertices[i].z;

        mesh->m_vertexes.push_back(vertex);
    }

    for (unsigned int j = 0; j < aiMesh->mNumFaces; ++j)
    {
        aiFace face = aiMesh->mFaces[j];
        for (unsigned int k = 0; k < face.mNumIndices; k++)
        {
            mesh->m_vertexesIndices.push_back(face.mIndices[k]);
            std::cout << face.mIndices[k] << std::endl;
        }
    }
}

void ModelLoader::TransformMatrix4(aiMatrix4x4& aiMat4, glm::mat4& glmMat4)
{
    glmMat4[0][0] = aiMat4[0][0];
    glmMat4[0][1] = aiMat4[1][0];
    glmMat4[0][2] = aiMat4[2][0];
    glmMat4[0][3] = aiMat4[3][0];


    glmMat4[1][0] = aiMat4[0][1];
    glmMat4[1][1] = aiMat4[1][1];
    glmMat4[1][2] = aiMat4[2][1];
    glmMat4[1][3] = aiMat4[3][1];


    glmMat4[2][0] = aiMat4[0][2];
    glmMat4[2][1] = aiMat4[1][2];
    glmMat4[2][2] = aiMat4[2][2];
    glmMat4[2][3] = aiMat4[3][2];

    glmMat4[3][0] = aiMat4[0][3];
    glmMat4[3][1] = aiMat4[1][3];
    glmMat4[3][2] = aiMat4[2][3];
    glmMat4[3][3] = aiMat4[3][3];
}

}